import { ref } from "vue";
import { DataGridColumn, DataGridProps } from "../data-grid.props";
import { CellMode, UseEdit, UseVisualDataBound, UseVisualDataCell, VisualData, VisualDataCell } from "./types";

export function useVisualDataCell(
    props: DataGridProps,
    useEditComposition: UseEdit,
    useVisualDataBoundComposition: UseVisualDataBound
): UseVisualDataCell {
    const mergingCell = ref(props.mergeCell);
    const rowOption = ref(props.rowOption);
    const autoRowHeight = rowOption.value?.wrapContent || false;
    const { updateVisualInfomation } = useVisualDataBoundComposition;

    function createCellByField(targetField: string, index: number, dataItem: any, parent: VisualData, colSpan = 1) {
        const targetCell: VisualDataCell = {
            colSpan,
            rowSpan: 1,
            index,
            field: targetField,
            data: dataItem[targetField],
            editingData: dataItem[targetField],
            parent,
            mode: CellMode.readonly,
            getEditor: (cell) => cell.data,
            setRef: (vnode: any) => updateVisualInfomation(vnode, targetCell, dataItem),
            update: () => { },
            accept: () => { },
            cancel: () => { }
        };
        return targetCell;
    }

    function wrapCellEditor(targetCell: VisualDataCell, column: DataGridColumn, dataItem: any) {
        targetCell.getEditor = (cell: VisualDataCell) => useEditComposition.getEditor(cell, column, cell.parent);
        targetCell.setRef = (vnode: any) => autoRowHeight && updateVisualInfomation(vnode, targetCell, dataItem);
        targetCell.update = (value: any) => { value !== undefined && (targetCell.editingData = value); };
        targetCell.accept = () => {
            dataItem[column.field] = targetCell.editingData;
            targetCell.data = dataItem[column.field];
        };
        targetCell.cancel = () => { targetCell.editingData = targetCell.data; };

        return targetCell;
    }

    function tryToWrapCellCommand(targetCell: VisualDataCell, column: DataGridColumn) {
        if (column.dataType === 'commands') {
            targetCell.formatter = (cell: VisualDataCell, visualDataRow: VisualData) => {
                return useEditComposition.getEditor(cell, column, visualDataRow);
            };
        }
    }

    function merginSameValueInColumn(currentCell: VisualDataCell, preDataItem: VisualData, columnField: string) {
        const preRowMerginSpan = preDataItem && preDataItem.data[columnField];
        const hasBeenSpanned = preRowMerginSpan && preRowMerginSpan.data === currentCell.data;
        if (hasBeenSpanned) {
            const spannedBy: VisualDataCell = (preRowMerginSpan && preRowMerginSpan.spannedBy) || preRowMerginSpan;
            spannedBy.rowSpan++;
            spannedBy.spanned = spannedBy.spanned || [];
            spannedBy.spanned.push(currentCell);
            currentCell.colSpan = 0;
            currentCell.rowSpan = 0;
            currentCell.spannedBy = spannedBy;
        }
    }

    function tryToMergeCellValue(targetCell: VisualDataCell, preMergingRow: VisualData, column: DataGridColumn) {
        if (mergingCell.value) {
            merginSameValueInColumn(targetCell, preMergingRow, column.field);
        }
    }

    function createCellByColumn(
        column: DataGridColumn, index: number, dataItem: any,
        parent: VisualData, preVisualData: VisualData
    ): VisualDataCell {
        const targetCell: VisualDataCell = createCellByField(column.field, index, dataItem, parent);
        wrapCellEditor(targetCell, column, dataItem);
        tryToWrapCellCommand(targetCell, column);
        tryToMergeCellValue(targetCell, preVisualData, column);
        return targetCell;
    }

    return { createCellByColumn, createCellByField };
}
